0x03. Unittests and Integration Tests
- Weight: 1
- Project will start Apr 4, 2024 6:00 AM, must end by Apr 9, 2024 6:00 AM
- Checker was released at Apr 5, 2024 12:00 PM
- An auto review will be launched at the deadline
Unit testing is the process of testing that a particular function returns expected results for different set of inputs. A unit test is supposed to test standard inputs and corner cases. A unit test should only test the logic defined inside the tested function. Most calls to additional functions should be mocked, especially if they make network or database calls.
The goal of a unit test is to answer the question: if everything defined outside this function works as expected, does this function work as expected?
Integration tests aim to test a code path end-to-end. In general, only low level functions that make external calls such as HTTP requests, file I/O, database I/O, etc. are mocked.
Integration tests will test interactions between every part of your code.
Execute your tests with
$ python -m unittest path/to/test_file.py
Resources
Read or watch:
- unittest — Unit testing framework
- unittest.mock — mock object library
- How to mock a readonly property with mock?
- parameterized
- Memoization
Learning Objectives
At the end of this project, you are expected to be able to explain to anyone, without the help of Google:
- The difference between unit and integration tests.
- Common testing patterns such as mocking, parametrizations and fixtures
Requirements
- All your files will be interpreted/compiled on Ubuntu 18.04 LTS using
python3(version 3.7) - All your files should end with a new line
- The first line of all your files should be exactly
#!/usr/bin/env python3 - A
README.mdfile, at the root of the folder of the project, is mandatory - Your code should use the
pycodestylestyle (version 2.5) - All your files must be executable
- All your modules should have a documentation
(
python3 -c 'print(__import__("my_module").__doc__)') - All your classes should have a documentation
(
python3 -c 'print(__import__("my_module").MyClass.__doc__)') - All your functions (inside and outside a class) should have a documentation
(
python3 -c 'print(__import__("my_module").my_function.__doc__)'andpython3 -c 'print(__import__("my_module").MyClass.my_function.__doc__)') - A documentation is not a simple word, it’s a real sentence explaining what’s the purpose of the module, class or method (the length of it will be verified)
- All your functions and coroutines must be type-annotated.
Required Files
utils.py (or download)
Click to show/hide file contents
#!/usr/bin/env python3
"""Generic utilities for github org client.
"""
import requests
from functools import wraps
from typing import (
Mapping,
Sequence,
Any,
Dict,
Callable,
)
__all__ = [
"access_nested_map",
"get_json",
"memoize",
]
def access_nested_map(nested_map: Mapping, path: Sequence) -> Any:
"""Access nested map with key path.
Parameters
----------
nested_map: Mapping
A nested map
path: Sequence
a sequence of key representing a path to the value
Example
-------
>>> nested_map = {"a": {"b": {"c": 1}}}
>>> access_nested_map(nested_map, ["a", "b", "c"])
1
"""
for key in path:
if not isinstance(nested_map, Mapping):
raise KeyError(key)
nested_map = nested_map[key]
return nested_map
def get_json(url: str) -> Dict:
"""Get JSON from remote URL.
"""
response = requests.get(url)
return response.json()
def memoize(fn: Callable) -> Callable:
"""Decorator to memoize a method.
Example
-------
class MyClass:
@memoize
def a_method(self):
print("a_method called")
return 42
>>> my_object = MyClass()
>>> my_object.a_method
a_method called
42
>>> my_object.a_method
42
"""
attr_name = "_{}".format(fn.__name__)
@wraps(fn)
def memoized(self):
""""memoized wraps"""
if not hasattr(self, attr_name):
setattr(self, attr_name, fn(self))
return getattr(self, attr_name)
return property(memoized)
client.py (or download)
Click to show/hide file contents
#!/usr/bin/env python3
"""A github org client
"""
from typing import (
List,
Dict,
)
from utils import (
get_json,
access_nested_map,
memoize,
)
class GithubOrgClient:
"""A Githib org client
"""
ORG_URL = "https://api.github.com/orgs/{org}"
def __init__(self, org_name: str) -> None:
"""Init method of GithubOrgClient"""
self._org_name = org_name
@memoize
def org(self) -> Dict:
"""Memoize org"""
return get_json(self.ORG_URL.format(org=self._org_name))
@property
def _public_repos_url(self) -> str:
"""Public repos URL"""
return self.org["repos_url"]
@memoize
def repos_payload(self) -> Dict:
"""Memoize repos payload"""
return get_json(self._public_repos_url)
def public_repos(self, license: str = None) -> List[str]:
"""Public repos"""
json_payload = self.repos_payload
public_repos = [
repo["name"] for repo in json_payload
if license is None or self.has_license(repo, license)
]
return public_repos
@staticmethod
def has_license(repo: Dict[str, Dict], license_key: str) -> bool:
"""Static: has_license"""
assert license_key is not None, "license_key cannot be None"
try:
has_license = access_nested_map(repo, ("license", "key")) == license_key
except KeyError:
return False
return has_license
fixtures.py (or download)
Click to show/hide file contents
#!/usr/bin/env python3
TEST_PAYLOAD = [
(
{"repos_url": "https://api.github.com/orgs/google/repos"},
[
{
"id": 7697149,
"node_id": "MDEwOlJlcG9zaXRvcnk3Njk3MTQ5",
"name": "episodes.dart",
"full_name": "google/episodes.dart",
"private": False,
"owner": {
"login": "google",
"id": 1342004,
"node_id": "MDEyOk9yZ2FuaXphdGlvbjEzNDIwMDQ=",
"avatar_url": "https://avatars1.githubusercontent.com/u/1342004?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/google",
"html_url": "https://github.com/google",
"followers_url": "https://api.github.com/users/google/followers",
"following_url": "https://api.github.com/users/google/following{/other_user}",
"gists_url": "https://api.github.com/users/google/gists{/gist_id}",
"starred_url": "https://api.github.com/users/google/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/google/subscriptions",
"organizations_url": "https://api.github.com/users/google/orgs",
"repos_url": "https://api.github.com/users/google/repos",
"events_url": "https://api.github.com/users/google/events{/privacy}",
"received_events_url": "https://api.github.com/users/google/received_events",
"type": "Organization",
"site_admin": False
},
"html_url": "https://github.com/google/episodes.dart",
"description": "A framework for timing performance of web apps.",
"fork": False,
"url": "https://api.github.com/repos/google/episodes.dart",
"forks_url": "https://api.github.com/repos/google/episodes.dart/forks",
"keys_url": "https://api.github.com/repos/google/episodes.dart/keys{/key_id}",
"collaborators_url": "https://api.github.com/repos/google/episodes.dart/collaborators{/collaborator}",
"teams_url": "https://api.github.com/repos/google/episodes.dart/teams",
"hooks_url": "https://api.github.com/repos/google/episodes.dart/hooks",
"issue_events_url": "https://api.github.com/repos/google/episodes.dart/issues/events{/number}",
"events_url": "https://api.github.com/repos/google/episodes.dart/events",
"assignees_url": "https://api.github.com/repos/google/episodes.dart/assignees{/user}",
"branches_url": "https://api.github.com/repos/google/episodes.dart/branches{/branch}",
"tags_url": "https://api.github.com/repos/google/episodes.dart/tags",
"blobs_url": "https://api.github.com/repos/google/episodes.dart/git/blobs{/sha}",
"git_tags_url": "https://api.github.com/repos/google/episodes.dart/git/tags{/sha}",
"git_refs_url": "https://api.github.com/repos/google/episodes.dart/git/refs{/sha}",
"trees_url": "https://api.github.com/repos/google/episodes.dart/git/trees{/sha}",
"statuses_url": "https://api.github.com/repos/google/episodes.dart/statuses/{sha}",
"languages_url": "https://api.github.com/repos/google/episodes.dart/languages",
"stargazers_url": "https://api.github.com/repos/google/episodes.dart/stargazers",
"contributors_url": "https://api.github.com/repos/google/episodes.dart/contributors",
"subscribers_url": "https://api.github.com/repos/google/episodes.dart/subscribers",
"subscription_url": "https://api.github.com/repos/google/episodes.dart/subscription",
"commits_url": "https://api.github.com/repos/google/episodes.dart/commits{/sha}",
"git_commits_url": "https://api.github.com/repos/google/episodes.dart/git/commits{/sha}",
"comments_url": "https://api.github.com/repos/google/episodes.dart/comments{/number}",
"issue_comment_url": "https://api.github.com/repos/google/episodes.dart/issues/comments{/number}",
"contents_url": "https://api.github.com/repos/google/episodes.dart/contents/{+path}",
"compare_url": "https://api.github.com/repos/google/episodes.dart/compare/{base}...{head}",
"merges_url": "https://api.github.com/repos/google/episodes.dart/merges",
"archive_url": "https://api.github.com/repos/google/episodes.dart/{archive_format}{/ref}",
"downloads_url": "https://api.github.com/repos/google/episodes.dart/downloads",
"issues_url": "https://api.github.com/repos/google/episodes.dart/issues{/number}",
"pulls_url": "https://api.github.com/repos/google/episodes.dart/pulls{/number}",
"milestones_url": "https://api.github.com/repos/google/episodes.dart/milestones{/number}",
"notifications_url": "https://api.github.com/repos/google/episodes.dart/notifications{?since,all,participating}",
"labels_url": "https://api.github.com/repos/google/episodes.dart/labels{/name}",
"releases_url": "https://api.github.com/repos/google/episodes.dart/releases{/id}",
"deployments_url": "https://api.github.com/repos/google/episodes.dart/deployments",
"created_at": "2013-01-19T00:31:37Z",
"updated_at": "2019-09-23T11:53:58Z",
"pushed_at": "2014-10-09T21:39:33Z",
"git_url": "git://github.com/google/episodes.dart.git",
"ssh_url": "git@github.com:google/episodes.dart.git",
"clone_url": "https://github.com/google/episodes.dart.git",
"svn_url": "https://github.com/google/episodes.dart",
"homepage": None,
"size": 191,
"stargazers_count": 12,
"watchers_count": 12,
"language": "Dart",
"has_issues": True,
"has_projects": True,
"has_downloads": True,
"has_wiki": True,
"has_pages": False,
"forks_count": 22,
"mirror_url": None,
"archived": False,
"disabled": False,
"open_issues_count": 0,
"license": {
"key": "bsd-3-clause",
"name": "BSD 3-Clause \"New\" or \"Revised\" License",
"spdx_id": "BSD-3-Clause",
"url": "https://api.github.com/licenses/bsd-3-clause",
"node_id": "MDc6TGljZW5zZTU="
},
"forks": 22,
"open_issues": 0,
"watchers": 12,
"default_branch": "master",
"permissions": {
"admin": False,
"push": False,
"pull": True
}
},
{
"id": 7776515,
"node_id": "MDEwOlJlcG9zaXRvcnk3Nzc2NTE1",
"name": "cpp-netlib",
"full_name": "google/cpp-netlib",
"private": False,
"owner": {
"login": "google",
"id": 1342004,
"node_id": "MDEyOk9yZ2FuaXphdGlvbjEzNDIwMDQ=",
"avatar_url": "https://avatars1.githubusercontent.com/u/1342004?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/google",
"html_url": "https://github.com/google",
"followers_url": "https://api.github.com/users/google/followers",
"following_url": "https://api.github.com/users/google/following{/other_user}",
"gists_url": "https://api.github.com/users/google/gists{/gist_id}",
"starred_url": "https://api.github.com/users/google/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/google/subscriptions",
"organizations_url": "https://api.github.com/users/google/orgs",
"repos_url": "https://api.github.com/users/google/repos",
"events_url": "https://api.github.com/users/google/events{/privacy}",
"received_events_url": "https://api.github.com/users/google/received_events",
"type": "Organization",
"site_admin": False
},
"html_url": "https://github.com/google/cpp-netlib",
"description": "The C++ Network Library Project -- header-only, cross-platform, standards compliant networking library.",
"fork": True,
"url": "https://api.github.com/repos/google/cpp-netlib",
"forks_url": "https://api.github.com/repos/google/cpp-netlib/forks",
"keys_url": "https://api.github.com/repos/google/cpp-netlib/keys{/key_id}",
"collaborators_url": "https://api.github.com/repos/google/cpp-netlib/collaborators{/collaborator}",
"teams_url": "https://api.github.com/repos/google/cpp-netlib/teams",
"hooks_url": "https://api.github.com/repos/google/cpp-netlib/hooks",
"issue_events_url": "https://api.github.com/repos/google/cpp-netlib/issues/events{/number}",
"events_url": "https://api.github.com/repos/google/cpp-netlib/events",
"assignees_url": "https://api.github.com/repos/google/cpp-netlib/assignees{/user}",
"branches_url": "https://api.github.com/repos/google/cpp-netlib/branches{/branch}",
"tags_url": "https://api.github.com/repos/google/cpp-netlib/tags",
"blobs_url": "https://api.github.com/repos/google/cpp-netlib/git/blobs{/sha}",
"git_tags_url": "https://api.github.com/repos/google/cpp-netlib/git/tags{/sha}",
"git_refs_url": "https://api.github.com/repos/google/cpp-netlib/git/refs{/sha}",
"trees_url": "https://api.github.com/repos/google/cpp-netlib/git/trees{/sha}",
"statuses_url": "https://api.github.com/repos/google/cpp-netlib/statuses/{sha}",
"languages_url": "https://api.github.com/repos/google/cpp-netlib/languages",
"stargazers_url": "https://api.github.com/repos/google/cpp-netlib/stargazers",
"contributors_url": "https://api.github.com/repos/google/cpp-netlib/contributors",
"subscribers_url": "https://api.github.com/repos/google/cpp-netlib/subscribers",
"subscription_url": "https://api.github.com/repos/google/cpp-netlib/subscription",
"commits_url": "https://api.github.com/repos/google/cpp-netlib/commits{/sha}",
"git_commits_url": "https://api.github.com/repos/google/cpp-netlib/git/commits{/sha}",
"comments_url": "https://api.github.com/repos/google/cpp-netlib/comments{/number}",
"issue_comment_url": "https://api.github.com/repos/google/cpp-netlib/issues/comments{/number}",
"contents_url": "https://api.github.com/repos/google/cpp-netlib/contents/{+path}",
"compare_url": "https://api.github.com/repos/google/cpp-netlib/compare/{base}...{head}",
"merges_url": "https://api.github.com/repos/google/cpp-netlib/merges",
"archive_url": "https://api.github.com/repos/google/cpp-netlib/{archive_format}{/ref}",
"downloads_url": "https://api.github.com/repos/google/cpp-netlib/downloads",
"issues_url": "https://api.github.com/repos/google/cpp-netlib/issues{/number}",
"pulls_url": "https://api.github.com/repos/google/cpp-netlib/pulls{/number}",
"milestones_url": "https://api.github.com/repos/google/cpp-netlib/milestones{/number}",
"notifications_url": "https://api.github.com/repos/google/cpp-netlib/notifications{?since,all,participating}",
"labels_url": "https://api.github.com/repos/google/cpp-netlib/labels{/name}",
"releases_url": "https://api.github.com/repos/google/cpp-netlib/releases{/id}",
"deployments_url": "https://api.github.com/repos/google/cpp-netlib/deployments",
"created_at": "2013-01-23T14:45:32Z",
"updated_at": "2019-11-15T02:26:31Z",
"pushed_at": "2018-12-05T17:42:29Z",
"git_url": "git://github.com/google/cpp-netlib.git",
"ssh_url": "git@github.com:google/cpp-netlib.git",
"clone_url": "https://github.com/google/cpp-netlib.git",
"svn_url": "https://github.com/google/cpp-netlib",
"homepage": "http://cpp-netlib.github.com/",
"size": 8937,
"stargazers_count": 292,
"watchers_count": 292,
"language": "C++",
"has_issues": False,
"has_projects": True,
"has_downloads": True,
"has_wiki": True,
"has_pages": False,
"forks_count": 59,
"mirror_url": None,
"archived": False,
"disabled": False,
"open_issues_count": 0,
"license": {
"key": "bsl-1.0",
"name": "Boost Software License 1.0",
"spdx_id": "BSL-1.0",
"url": "https://api.github.com/licenses/bsl-1.0",
"node_id": "MDc6TGljZW5zZTI4"
},
"forks": 59,
"open_issues": 0,
"watchers": 292,
"default_branch": "master",
"permissions": {
"admin": False,
"push": False,
"pull": True
}
},
{
"id": 7968417,
"node_id": "MDEwOlJlcG9zaXRvcnk3OTY4NDE3",
"name": "dagger",
"full_name": "google/dagger",
"private": False,
"owner": {
"login": "google",
"id": 1342004,
"node_id": "MDEyOk9yZ2FuaXphdGlvbjEzNDIwMDQ=",
"avatar_url": "https://avatars1.githubusercontent.com/u/1342004?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/google",
"html_url": "https://github.com/google",
"followers_url": "https://api.github.com/users/google/followers",
"following_url": "https://api.github.com/users/google/following{/other_user}",
"gists_url": "https://api.github.com/users/google/gists{/gist_id}",
"starred_url": "https://api.github.com/users/google/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/google/subscriptions",
"organizations_url": "https://api.github.com/users/google/orgs",
"repos_url": "https://api.github.com/users/google/repos",
"events_url": "https://api.github.com/users/google/events{/privacy}",
"received_events_url": "https://api.github.com/users/google/received_events",
"type": "Organization",
"site_admin": False
},
"html_url": "https://github.com/google/dagger",
"description": "A fast dependency injector for Android and Java.",
"fork": True,
"url": "https://api.github.com/repos/google/dagger",
"forks_url": "https://api.github.com/repos/google/dagger/forks",
"keys_url": "https://api.github.com/repos/google/dagger/keys{/key_id}",
"collaborators_url": "https://api.github.com/repos/google/dagger/collaborators{/collaborator}",
"teams_url": "https://api.github.com/repos/google/dagger/teams",
"hooks_url": "https://api.github.com/repos/google/dagger/hooks",
"issue_events_url": "https://api.github.com/repos/google/dagger/issues/events{/number}",
"events_url": "https://api.github.com/repos/google/dagger/events",
"assignees_url": "https://api.github.com/repos/google/dagger/assignees{/user}",
"branches_url": "https://api.github.com/repos/google/dagger/branches{/branch}",
"tags_url": "https://api.github.com/repos/google/dagger/tags",
"blobs_url": "https://api.github.com/repos/google/dagger/git/blobs{/sha}",
"git_tags_url": "https://api.github.com/repos/google/dagger/git/tags{/sha}",
"git_refs_url": "https://api.github.com/repos/google/dagger/git/refs{/sha}",
"trees_url": "https://api.github.com/repos/google/dagger/git/trees{/sha}",
"statuses_url": "https://api.github.com/repos/google/dagger/statuses/{sha}",
"languages_url": "https://api.github.com/repos/google/dagger/languages",
"stargazers_url": "https://api.github.com/repos/google/dagger/stargazers",
"contributors_url": "https://api.github.com/repos/google/dagger/contributors",
"subscribers_url": "https://api.github.com/repos/google/dagger/subscribers",
"subscription_url": "https://api.github.com/repos/google/dagger/subscription",
"commits_url": "https://api.github.com/repos/google/dagger/commits{/sha}",
"git_commits_url": "https://api.github.com/repos/google/dagger/git/commits{/sha}",
"comments_url": "https://api.github.com/repos/google/dagger/comments{/number}",
"issue_comment_url": "https://api.github.com/repos/google/dagger/issues/comments{/number}",
"contents_url": "https://api.github.com/repos/google/dagger/contents/{+path}",
"compare_url": "https://api.github.com/repos/google/dagger/compare/{base}...{head}",
"merges_url": "https://api.github.com/repos/google/dagger/merges",
"archive_url": "https://api.github.com/repos/google/dagger/{archive_format}{/ref}",
"downloads_url": "https://api.github.com/repos/google/dagger/downloads",
"issues_url": "https://api.github.com/repos/google/dagger/issues{/number}",
"pulls_url": "https://api.github.com/repos/google/dagger/pulls{/number}",
"milestones_url": "https://api.github.com/repos/google/dagger/milestones{/number}",
"notifications_url": "https://api.github.com/repos/google/dagger/notifications{?since,all,participating}",
"labels_url": "https://api.github.com/repos/google/dagger/labels{/name}",
"releases_url": "https://api.github.com/repos/google/dagger/releases{/id}",
"deployments_url": "https://api.github.com/repos/google/dagger/deployments",
"created_at": "2013-02-01T23:14:14Z",
"updated_at": "2019-12-03T12:39:55Z",
"pushed_at": "2019-11-27T21:20:38Z",
"git_url": "git://github.com/google/dagger.git",
"ssh_url": "git@github.com:google/dagger.git",
"clone_url": "https://github.com/google/dagger.git",
"svn_url": "https://github.com/google/dagger",
"homepage": "https://dagger.dev",
"size": 59129,
"stargazers_count": 14492,
"watchers_count": 14492,
"language": "Java",
"has_issues": True,
"has_projects": True,
"has_downloads": True,
"has_wiki": True,
"has_pages": True,
"forks_count": 1741,
"mirror_url": None,
"archived": False,
"disabled": False,
"open_issues_count": 148,
"license": {
"key": "apache-2.0",
"name": "Apache License 2.0",
"spdx_id": "Apache-2.0",
"url": "https://api.github.com/licenses/apache-2.0",
"node_id": "MDc6TGljZW5zZTI="
},
"forks": 1741,
"open_issues": 148,
"watchers": 14492,
"default_branch": "master",
"permissions": {
"admin": False,
"push": False,
"pull": True
}
},
{
"id": 8165161,
"node_id": "MDEwOlJlcG9zaXRvcnk4MTY1MTYx",
"name": "ios-webkit-debug-proxy",
"full_name": "google/ios-webkit-debug-proxy",
"private": False,
"owner": {
"login": "google",
"id": 1342004,
"node_id": "MDEyOk9yZ2FuaXphdGlvbjEzNDIwMDQ=",
"avatar_url": "https://avatars1.githubusercontent.com/u/1342004?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/google",
"html_url": "https://github.com/google",
"followers_url": "https://api.github.com/users/google/followers",
"following_url": "https://api.github.com/users/google/following{/other_user}",
"gists_url": "https://api.github.com/users/google/gists{/gist_id}",
"starred_url": "https://api.github.com/users/google/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/google/subscriptions",
"organizations_url": "https://api.github.com/users/google/orgs",
"repos_url": "https://api.github.com/users/google/repos",
"events_url": "https://api.github.com/users/google/events{/privacy}",
"received_events_url": "https://api.github.com/users/google/received_events",
"type": "Organization",
"site_admin": False
},
"html_url": "https://github.com/google/ios-webkit-debug-proxy",
"description": "A DevTools proxy (Chrome Remote Debugging Protocol) for iOS devices (Safari Remote Web Inspector).",
"fork": False,
"url": "https://api.github.com/repos/google/ios-webkit-debug-proxy",
"forks_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/forks",
"keys_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/keys{/key_id}",
"collaborators_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/collaborators{/collaborator}",
"teams_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/teams",
"hooks_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/hooks",
"issue_events_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/issues/events{/number}",
"events_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/events",
"assignees_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/assignees{/user}",
"branches_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/branches{/branch}",
"tags_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/tags",
"blobs_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/git/blobs{/sha}",
"git_tags_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/git/tags{/sha}",
"git_refs_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/git/refs{/sha}",
"trees_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/git/trees{/sha}",
"statuses_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/statuses/{sha}",
"languages_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/languages",
"stargazers_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/stargazers",
"contributors_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/contributors",
"subscribers_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/subscribers",
"subscription_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/subscription",
"commits_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/commits{/sha}",
"git_commits_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/git/commits{/sha}",
"comments_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/comments{/number}",
"issue_comment_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/issues/comments{/number}",
"contents_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/contents/{+path}",
"compare_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/compare/{base}...{head}",
"merges_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/merges",
"archive_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/{archive_format}{/ref}",
"downloads_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/downloads",
"issues_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/issues{/number}",
"pulls_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/pulls{/number}",
"milestones_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/milestones{/number}",
"notifications_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/notifications{?since,all,participating}",
"labels_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/labels{/name}",
"releases_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/releases{/id}",
"deployments_url": "https://api.github.com/repos/google/ios-webkit-debug-proxy/deployments",
"created_at": "2013-02-12T19:08:19Z",
"updated_at": "2019-12-04T02:06:43Z",
"pushed_at": "2019-11-24T07:02:13Z",
"git_url": "git://github.com/google/ios-webkit-debug-proxy.git",
"ssh_url": "git@github.com:google/ios-webkit-debug-proxy.git",
"clone_url": "https://github.com/google/ios-webkit-debug-proxy.git",
"svn_url": "https://github.com/google/ios-webkit-debug-proxy",
"homepage": "",
"size": 680,
"stargazers_count": 4630,
"watchers_count": 4630,
"language": "C",
"has_issues": True,
"has_projects": True,
"has_downloads": True,
"has_wiki": False,
"has_pages": False,
"forks_count": 395,
"mirror_url": None,
"archived": False,
"disabled": False,
"open_issues_count": 24,
"license": {
"key": "other",
"name": "Other",
"spdx_id": "NOASSERTION",
"url": None,
"node_id": "MDc6TGljZW5zZTA="
},
"forks": 395,
"open_issues": 24,
"watchers": 4630,
"default_branch": "master",
"permissions": {
"admin": False,
"push": False,
"pull": True
}
},
{
"id": 8459994,
"node_id": "MDEwOlJlcG9zaXRvcnk4NDU5OTk0",
"name": "google.github.io",
"full_name": "google/google.github.io",
"private": False,
"owner": {
"login": "google",
"id": 1342004,
"node_id": "MDEyOk9yZ2FuaXphdGlvbjEzNDIwMDQ=",
"avatar_url": "https://avatars1.githubusercontent.com/u/1342004?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/google",
"html_url": "https://github.com/google",
"followers_url": "https://api.github.com/users/google/followers",
"following_url": "https://api.github.com/users/google/following{/other_user}",
"gists_url": "https://api.github.com/users/google/gists{/gist_id}",
"starred_url": "https://api.github.com/users/google/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/google/subscriptions",
"organizations_url": "https://api.github.com/users/google/orgs",
"repos_url": "https://api.github.com/users/google/repos",
"events_url": "https://api.github.com/users/google/events{/privacy}",
"received_events_url": "https://api.github.com/users/google/received_events",
"type": "Organization",
"site_admin": False
},
"html_url": "https://github.com/google/google.github.io",
"description": None,
"fork": False,
"url": "https://api.github.com/repos/google/google.github.io",
"forks_url": "https://api.github.com/repos/google/google.github.io/forks",
"keys_url": "https://api.github.com/repos/google/google.github.io/keys{/key_id}",
"collaborators_url": "https://api.github.com/repos/google/google.github.io/collaborators{/collaborator}",
"teams_url": "https://api.github.com/repos/google/google.github.io/teams",
"hooks_url": "https://api.github.com/repos/google/google.github.io/hooks",
"issue_events_url": "https://api.github.com/repos/google/google.github.io/issues/events{/number}",
"events_url": "https://api.github.com/repos/google/google.github.io/events",
"assignees_url": "https://api.github.com/repos/google/google.github.io/assignees{/user}",
"branches_url": "https://api.github.com/repos/google/google.github.io/branches{/branch}",
"tags_url": "https://api.github.com/repos/google/google.github.io/tags",
"blobs_url": "https://api.github.com/repos/google/google.github.io/git/blobs{/sha}",
"git_tags_url": "https://api.github.com/repos/google/google.github.io/git/tags{/sha}",
"git_refs_url": "https://api.github.com/repos/google/google.github.io/git/refs{/sha}",
"trees_url": "https://api.github.com/repos/google/google.github.io/git/trees{/sha}",
"statuses_url": "https://api.github.com/repos/google/google.github.io/statuses/{sha}",
"languages_url": "https://api.github.com/repos/google/google.github.io/languages",
"stargazers_url": "https://api.github.com/repos/google/google.github.io/stargazers",
"contributors_url": "https://api.github.com/repos/google/google.github.io/contributors",
"subscribers_url": "https://api.github.com/repos/google/google.github.io/subscribers",
"subscription_url": "https://api.github.com/repos/google/google.github.io/subscription",
"commits_url": "https://api.github.com/repos/google/google.github.io/commits{/sha}",
"git_commits_url": "https://api.github.com/repos/google/google.github.io/git/commits{/sha}",
"comments_url": "https://api.github.com/repos/google/google.github.io/comments{/number}",
"issue_comment_url": "https://api.github.com/repos/google/google.github.io/issues/comments{/number}",
"contents_url": "https://api.github.com/repos/google/google.github.io/contents/{+path}",
"compare_url": "https://api.github.com/repos/google/google.github.io/compare/{base}...{head}",
"merges_url": "https://api.github.com/repos/google/google.github.io/merges",
"archive_url": "https://api.github.com/repos/google/google.github.io/{archive_format}{/ref}",
"downloads_url": "https://api.github.com/repos/google/google.github.io/downloads",
"issues_url": "https://api.github.com/repos/google/google.github.io/issues{/number}",
"pulls_url": "https://api.github.com/repos/google/google.github.io/pulls{/number}",
"milestones_url": "https://api.github.com/repos/google/google.github.io/milestones{/number}",
"notifications_url": "https://api.github.com/repos/google/google.github.io/notifications{?since,all,participating}",
"labels_url": "https://api.github.com/repos/google/google.github.io/labels{/name}",
"releases_url": "https://api.github.com/repos/google/google.github.io/releases{/id}",
"deployments_url": "https://api.github.com/repos/google/google.github.io/deployments",
"created_at": "2013-02-27T16:21:19Z",
"updated_at": "2019-12-03T01:38:02Z",
"pushed_at": "2019-12-03T01:37:58Z",
"git_url": "git://github.com/google/google.github.io.git",
"ssh_url": "git@github.com:google/google.github.io.git",
"clone_url": "https://github.com/google/google.github.io.git",
"svn_url": "https://github.com/google/google.github.io",
"homepage": None,
"size": 8,
"stargazers_count": 38,
"watchers_count": 38,
"language": "HTML",
"has_issues": False,
"has_projects": True,
"has_downloads": True,
"has_wiki": False,
"has_pages": True,
"forks_count": 44,
"mirror_url": None,
"archived": False,
"disabled": False,
"open_issues_count": 0,
"license": None,
"forks": 44,
"open_issues": 0,
"watchers": 38,
"default_branch": "master",
"permissions": {
"admin": False,
"push": False,
"pull": True
}
},
{
"id": 8566972,
"node_id": "MDEwOlJlcG9zaXRvcnk4NTY2OTcy",
"name": "kratu",
"full_name": "google/kratu",
"private": False,
"owner": {
"login": "google",
"id": 1342004,
"node_id": "MDEyOk9yZ2FuaXphdGlvbjEzNDIwMDQ=",
"avatar_url": "https://avatars1.githubusercontent.com/u/1342004?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/google",
"html_url": "https://github.com/google",
"followers_url": "https://api.github.com/users/google/followers",
"following_url": "https://api.github.com/users/google/following{/other_user}",
"gists_url": "https://api.github.com/users/google/gists{/gist_id}",
"starred_url": "https://api.github.com/users/google/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/google/subscriptions",
"organizations_url": "https://api.github.com/users/google/orgs",
"repos_url": "https://api.github.com/users/google/repos",
"events_url": "https://api.github.com/users/google/events{/privacy}",
"received_events_url": "https://api.github.com/users/google/received_events",
"type": "Organization",
"site_admin": False
},
"html_url": "https://github.com/google/kratu",
"description": None,
"fork": False,
"url": "https://api.github.com/repos/google/kratu",
"forks_url": "https://api.github.com/repos/google/kratu/forks",
"keys_url": "https://api.github.com/repos/google/kratu/keys{/key_id}",
"collaborators_url": "https://api.github.com/repos/google/kratu/collaborators{/collaborator}",
"teams_url": "https://api.github.com/repos/google/kratu/teams",
"hooks_url": "https://api.github.com/repos/google/kratu/hooks",
"issue_events_url": "https://api.github.com/repos/google/kratu/issues/events{/number}",
"events_url": "https://api.github.com/repos/google/kratu/events",
"assignees_url": "https://api.github.com/repos/google/kratu/assignees{/user}",
"branches_url": "https://api.github.com/repos/google/kratu/branches{/branch}",
"tags_url": "https://api.github.com/repos/google/kratu/tags",
"blobs_url": "https://api.github.com/repos/google/kratu/git/blobs{/sha}",
"git_tags_url": "https://api.github.com/repos/google/kratu/git/tags{/sha}",
"git_refs_url": "https://api.github.com/repos/google/kratu/git/refs{/sha}",
"trees_url": "https://api.github.com/repos/google/kratu/git/trees{/sha}",
"statuses_url": "https://api.github.com/repos/google/kratu/statuses/{sha}",
"languages_url": "https://api.github.com/repos/google/kratu/languages",
"stargazers_url": "https://api.github.com/repos/google/kratu/stargazers",
"contributors_url": "https://api.github.com/repos/google/kratu/contributors",
"subscribers_url": "https://api.github.com/repos/google/kratu/subscribers",
"subscription_url": "https://api.github.com/repos/google/kratu/subscription",
"commits_url": "https://api.github.com/repos/google/kratu/commits{/sha}",
"git_commits_url": "https://api.github.com/repos/google/kratu/git/commits{/sha}",
"comments_url": "https://api.github.com/repos/google/kratu/comments{/number}",
"issue_comment_url": "https://api.github.com/repos/google/kratu/issues/comments{/number}",
"contents_url": "https://api.github.com/repos/google/kratu/contents/{+path}",
"compare_url": "https://api.github.com/repos/google/kratu/compare/{base}...{head}",
"merges_url": "https://api.github.com/repos/google/kratu/merges",
"archive_url": "https://api.github.com/repos/google/kratu/{archive_format}{/ref}",
"downloads_url": "https://api.github.com/repos/google/kratu/downloads",
"issues_url": "https://api.github.com/repos/google/kratu/issues{/number}",
"pulls_url": "https://api.github.com/repos/google/kratu/pulls{/number}",
"milestones_url": "https://api.github.com/repos/google/kratu/milestones{/number}",
"notifications_url": "https://api.github.com/repos/google/kratu/notifications{?since,all,participating}",
"labels_url": "https://api.github.com/repos/google/kratu/labels{/name}",
"releases_url": "https://api.github.com/repos/google/kratu/releases{/id}",
"deployments_url": "https://api.github.com/repos/google/kratu/deployments",
"created_at": "2013-03-04T22:52:33Z",
"updated_at": "2019-11-15T22:22:16Z",
"pushed_at": "2017-08-06T05:44:34Z",
"git_url": "git://github.com/google/kratu.git",
"ssh_url": "git@github.com:google/kratu.git",
"clone_url": "https://github.com/google/kratu.git",
"svn_url": "https://github.com/google/kratu",
"homepage": None,
"size": 1777,
"stargazers_count": 280,
"watchers_count": 280,
"language": "JavaScript",
"has_issues": True,
"has_projects": True,
"has_downloads": True,
"has_wiki": True,
"has_pages": True,
"forks_count": 32,
"mirror_url": None,
"archived": False,
"disabled": False,
"open_issues_count": 0,
"license": {
"key": "apache-2.0",
"name": "Apache License 2.0",
"spdx_id": "Apache-2.0",
"url": "https://api.github.com/licenses/apache-2.0",
"node_id": "MDc6TGljZW5zZTI="
},
"forks": 32,
"open_issues": 0,
"watchers": 280,
"default_branch": "master",
"permissions": {
"admin": False,
"push": False,
"pull": True
}
},
{
"id": 8858648,
"node_id": "MDEwOlJlcG9zaXRvcnk4ODU4NjQ4",
"name": "build-debian-cloud",
"full_name": "google/build-debian-cloud",
"private": False,
"owner": {
"login": "google",
"id": 1342004,
"node_id": "MDEyOk9yZ2FuaXphdGlvbjEzNDIwMDQ=",
"avatar_url": "https://avatars1.githubusercontent.com/u/1342004?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/google",
"html_url": "https://github.com/google",
"followers_url": "https://api.github.com/users/google/followers",
"following_url": "https://api.github.com/users/google/following{/other_user}",
"gists_url": "https://api.github.com/users/google/gists{/gist_id}",
"starred_url": "https://api.github.com/users/google/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/google/subscriptions",
"organizations_url": "https://api.github.com/users/google/orgs",
"repos_url": "https://api.github.com/users/google/repos",
"events_url": "https://api.github.com/users/google/events{/privacy}",
"received_events_url": "https://api.github.com/users/google/received_events",
"type": "Organization",
"site_admin": False
},
"html_url": "https://github.com/google/build-debian-cloud",
"description": "Script to create Debian Squeeze & Wheezy Amazon Machine Images (AMIs) and Google Compute Engine images",
"fork": True,
"url": "https://api.github.com/repos/google/build-debian-cloud",
"forks_url": "https://api.github.com/repos/google/build-debian-cloud/forks",
"keys_url": "https://api.github.com/repos/google/build-debian-cloud/keys{/key_id}",
"collaborators_url": "https://api.github.com/repos/google/build-debian-cloud/collaborators{/collaborator}",
"teams_url": "https://api.github.com/repos/google/build-debian-cloud/teams",
"hooks_url": "https://api.github.com/repos/google/build-debian-cloud/hooks",
"issue_events_url": "https://api.github.com/repos/google/build-debian-cloud/issues/events{/number}",
"events_url": "https://api.github.com/repos/google/build-debian-cloud/events",
"assignees_url": "https://api.github.com/repos/google/build-debian-cloud/assignees{/user}",
"branches_url": "https://api.github.com/repos/google/build-debian-cloud/branches{/branch}",
"tags_url": "https://api.github.com/repos/google/build-debian-cloud/tags",
"blobs_url": "https://api.github.com/repos/google/build-debian-cloud/git/blobs{/sha}",
"git_tags_url": "https://api.github.com/repos/google/build-debian-cloud/git/tags{/sha}",
"git_refs_url": "https://api.github.com/repos/google/build-debian-cloud/git/refs{/sha}",
"trees_url": "https://api.github.com/repos/google/build-debian-cloud/git/trees{/sha}",
"statuses_url": "https://api.github.com/repos/google/build-debian-cloud/statuses/{sha}",
"languages_url": "https://api.github.com/repos/google/build-debian-cloud/languages",
"stargazers_url": "https://api.github.com/repos/google/build-debian-cloud/stargazers",
"contributors_url": "https://api.github.com/repos/google/build-debian-cloud/contributors",
"subscribers_url": "https://api.github.com/repos/google/build-debian-cloud/subscribers",
"subscription_url": "https://api.github.com/repos/google/build-debian-cloud/subscription",
"commits_url": "https://api.github.com/repos/google/build-debian-cloud/commits{/sha}",
"git_commits_url": "https://api.github.com/repos/google/build-debian-cloud/git/commits{/sha}",
"comments_url": "https://api.github.com/repos/google/build-debian-cloud/comments{/number}",
"issue_comment_url": "https://api.github.com/repos/google/build-debian-cloud/issues/comments{/number}",
"contents_url": "https://api.github.com/repos/google/build-debian-cloud/contents/{+path}",
"compare_url": "https://api.github.com/repos/google/build-debian-cloud/compare/{base}...{head}",
"merges_url": "https://api.github.com/repos/google/build-debian-cloud/merges",
"archive_url": "https://api.github.com/repos/google/build-debian-cloud/{archive_format}{/ref}",
"downloads_url": "https://api.github.com/repos/google/build-debian-cloud/downloads",
"issues_url": "https://api.github.com/repos/google/build-debian-cloud/issues{/number}",
"pulls_url": "https://api.github.com/repos/google/build-debian-cloud/pulls{/number}",
"milestones_url": "https://api.github.com/repos/google/build-debian-cloud/milestones{/number}",
"notifications_url": "https://api.github.com/repos/google/build-debian-cloud/notifications{?since,all,participating}",
"labels_url": "https://api.github.com/repos/google/build-debian-cloud/labels{/name}",
"releases_url": "https://api.github.com/repos/google/build-debian-cloud/releases{/id}",
"deployments_url": "https://api.github.com/repos/google/build-debian-cloud/deployments",
"created_at": "2013-03-18T16:32:00Z",
"updated_at": "2019-09-23T11:54:00Z",
"pushed_at": "2014-06-17T18:52:10Z",
"git_url": "git://github.com/google/build-debian-cloud.git",
"ssh_url": "git@github.com:google/build-debian-cloud.git",
"clone_url": "https://github.com/google/build-debian-cloud.git",
"svn_url": "https://github.com/google/build-debian-cloud",
"homepage": "",
"size": 986,
"stargazers_count": 32,
"watchers_count": 32,
"language": "Shell",
"has_issues": False,
"has_projects": True,
"has_downloads": True,
"has_wiki": False,
"has_pages": False,
"forks_count": 22,
"mirror_url": None,
"archived": False,
"disabled": False,
"open_issues_count": 5,
"license": {
"key": "other",
"name": "Other",
"spdx_id": "NOASSERTION",
"url": None,
"node_id": "MDc6TGljZW5zZTA="
},
"forks": 22,
"open_issues": 5,
"watchers": 32,
"default_branch": "master",
"permissions": {
"admin": False,
"push": False,
"pull": True
}
},
{
"id": 9060347,
"node_id": "MDEwOlJlcG9zaXRvcnk5MDYwMzQ3",
"name": "traceur-compiler",
"full_name": "google/traceur-compiler",
"private": False,
"owner": {
"login": "google",
"id": 1342004,
"node_id": "MDEyOk9yZ2FuaXphdGlvbjEzNDIwMDQ=",
"avatar_url": "https://avatars1.githubusercontent.com/u/1342004?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/google",
"html_url": "https://github.com/google",
"followers_url": "https://api.github.com/users/google/followers",
"following_url": "https://api.github.com/users/google/following{/other_user}",
"gists_url": "https://api.github.com/users/google/gists{/gist_id}",
"starred_url": "https://api.github.com/users/google/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/google/subscriptions",
"organizations_url": "https://api.github.com/users/google/orgs",
"repos_url": "https://api.github.com/users/google/repos",
"events_url": "https://api.github.com/users/google/events{/privacy}",
"received_events_url": "https://api.github.com/users/google/received_events",
"type": "Organization",
"site_admin": False
},
"html_url": "https://github.com/google/traceur-compiler",
"description": "Traceur is a JavaScript.next-to-JavaScript-of-today compiler",
"fork": False,
"url": "https://api.github.com/repos/google/traceur-compiler",
"forks_url": "https://api.github.com/repos/google/traceur-compiler/forks",
"keys_url": "https://api.github.com/repos/google/traceur-compiler/keys{/key_id}",
"collaborators_url": "https://api.github.com/repos/google/traceur-compiler/collaborators{/collaborator}",
"teams_url": "https://api.github.com/repos/google/traceur-compiler/teams",
"hooks_url": "https://api.github.com/repos/google/traceur-compiler/hooks",
"issue_events_url": "https://api.github.com/repos/google/traceur-compiler/issues/events{/number}",
"events_url": "https://api.github.com/repos/google/traceur-compiler/events",
"assignees_url": "https://api.github.com/repos/google/traceur-compiler/assignees{/user}",
"branches_url": "https://api.github.com/repos/google/traceur-compiler/branches{/branch}",
"tags_url": "https://api.github.com/repos/google/traceur-compiler/tags",
"blobs_url": "https://api.github.com/repos/google/traceur-compiler/git/blobs{/sha}",
"git_tags_url": "https://api.github.com/repos/google/traceur-compiler/git/tags{/sha}",
"git_refs_url": "https://api.github.com/repos/google/traceur-compiler/git/refs{/sha}",
"trees_url": "https://api.github.com/repos/google/traceur-compiler/git/trees{/sha}",
"statuses_url": "https://api.github.com/repos/google/traceur-compiler/statuses/{sha}",
"languages_url": "https://api.github.com/repos/google/traceur-compiler/languages",
"stargazers_url": "https://api.github.com/repos/google/traceur-compiler/stargazers",
"contributors_url": "https://api.github.com/repos/google/traceur-compiler/contributors",
"subscribers_url": "https://api.github.com/repos/google/traceur-compiler/subscribers",
"subscription_url": "https://api.github.com/repos/google/traceur-compiler/subscription",
"commits_url": "https://api.github.com/repos/google/traceur-compiler/commits{/sha}",
"git_commits_url": "https://api.github.com/repos/google/traceur-compiler/git/commits{/sha}",
"comments_url": "https://api.github.com/repos/google/traceur-compiler/comments{/number}",
"issue_comment_url": "https://api.github.com/repos/google/traceur-compiler/issues/comments{/number}",
"contents_url": "https://api.github.com/repos/google/traceur-compiler/contents/{+path}",
"compare_url": "https://api.github.com/repos/google/traceur-compiler/compare/{base}...{head}",
"merges_url": "https://api.github.com/repos/google/traceur-compiler/merges",
"archive_url": "https://api.github.com/repos/google/traceur-compiler/{archive_format}{/ref}",
"downloads_url": "https://api.github.com/repos/google/traceur-compiler/downloads",
"issues_url": "https://api.github.com/repos/google/traceur-compiler/issues{/number}",
"pulls_url": "https://api.github.com/repos/google/traceur-compiler/pulls{/number}",
"milestones_url": "https://api.github.com/repos/google/traceur-compiler/milestones{/number}",
"notifications_url": "https://api.github.com/repos/google/traceur-compiler/notifications{?since,all,participating}",
"labels_url": "https://api.github.com/repos/google/traceur-compiler/labels{/name}",
"releases_url": "https://api.github.com/repos/google/traceur-compiler/releases{/id}",
"deployments_url": "https://api.github.com/repos/google/traceur-compiler/deployments",
"created_at": "2013-03-27T18:05:40Z",
"updated_at": "2019-12-02T16:45:54Z",
"pushed_at": "2018-05-28T04:37:54Z",
"git_url": "git://github.com/google/traceur-compiler.git",
"ssh_url": "git@github.com:google/traceur-compiler.git",
"clone_url": "https://github.com/google/traceur-compiler.git",
"svn_url": "https://github.com/google/traceur-compiler",
"homepage": "",
"size": 27487,
"stargazers_count": 8033,
"watchers_count": 8033,
"language": "JavaScript",
"has_issues": True,
"has_projects": True,
"has_downloads": True,
"has_wiki": True,
"has_pages": True,
"forks_count": 604,
"mirror_url": None,
"archived": False,
"disabled": False,
"open_issues_count": 296,
"license": {
"key": "apache-2.0",
"name": "Apache License 2.0",
"spdx_id": "Apache-2.0",
"url": "https://api.github.com/licenses/apache-2.0",
"node_id": "MDc6TGljZW5zZTI="
},
"forks": 604,
"open_issues": 296,
"watchers": 8033,
"default_branch": "master",
"permissions": {
"admin": False,
"push": False,
"pull": True
}
},
{
"id": 9065917,
"node_id": "MDEwOlJlcG9zaXRvcnk5MDY1OTE3",
"name": "firmata.py",
"full_name": "google/firmata.py",
"private": False,
"owner": {
"login": "google",
"id": 1342004,
"node_id": "MDEyOk9yZ2FuaXphdGlvbjEzNDIwMDQ=",
"avatar_url": "https://avatars1.githubusercontent.com/u/1342004?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/google",
"html_url": "https://github.com/google",
"followers_url": "https://api.github.com/users/google/followers",
"following_url": "https://api.github.com/users/google/following{/other_user}",
"gists_url": "https://api.github.com/users/google/gists{/gist_id}",
"starred_url": "https://api.github.com/users/google/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/google/subscriptions",
"organizations_url": "https://api.github.com/users/google/orgs",
"repos_url": "https://api.github.com/users/google/repos",
"events_url": "https://api.github.com/users/google/events{/privacy}",
"received_events_url": "https://api.github.com/users/google/received_events",
"type": "Organization",
"site_admin": False
},
"html_url": "https://github.com/google/firmata.py",
"description": None,
"fork": False,
"url": "https://api.github.com/repos/google/firmata.py",
"forks_url": "https://api.github.com/repos/google/firmata.py/forks",
"keys_url": "https://api.github.com/repos/google/firmata.py/keys{/key_id}",
"collaborators_url": "https://api.github.com/repos/google/firmata.py/collaborators{/collaborator}",
"teams_url": "https://api.github.com/repos/google/firmata.py/teams",
"hooks_url": "https://api.github.com/repos/google/firmata.py/hooks",
"issue_events_url": "https://api.github.com/repos/google/firmata.py/issues/events{/number}",
"events_url": "https://api.github.com/repos/google/firmata.py/events",
"assignees_url": "https://api.github.com/repos/google/firmata.py/assignees{/user}",
"branches_url": "https://api.github.com/repos/google/firmata.py/branches{/branch}",
"tags_url": "https://api.github.com/repos/google/firmata.py/tags",
"blobs_url": "https://api.github.com/repos/google/firmata.py/git/blobs{/sha}",
"git_tags_url": "https://api.github.com/repos/google/firmata.py/git/tags{/sha}",
"git_refs_url": "https://api.github.com/repos/google/firmata.py/git/refs{/sha}",
"trees_url": "https://api.github.com/repos/google/firmata.py/git/trees{/sha}",
"statuses_url": "https://api.github.com/repos/google/firmata.py/statuses/{sha}",
"languages_url": "https://api.github.com/repos/google/firmata.py/languages",
"stargazers_url": "https://api.github.com/repos/google/firmata.py/stargazers",
"contributors_url": "https://api.github.com/repos/google/firmata.py/contributors",
"subscribers_url": "https://api.github.com/repos/google/firmata.py/subscribers",
"subscription_url": "https://api.github.com/repos/google/firmata.py/subscription",
"commits_url": "https://api.github.com/repos/google/firmata.py/commits{/sha}",
"git_commits_url": "https://api.github.com/repos/google/firmata.py/git/commits{/sha}",
"comments_url": "https://api.github.com/repos/google/firmata.py/comments{/number}",
"issue_comment_url": "https://api.github.com/repos/google/firmata.py/issues/comments{/number}",
"contents_url": "https://api.github.com/repos/google/firmata.py/contents/{+path}",
"compare_url": "https://api.github.com/repos/google/firmata.py/compare/{base}...{head}",
"merges_url": "https://api.github.com/repos/google/firmata.py/merges",
"archive_url": "https://api.github.com/repos/google/firmata.py/{archive_format}{/ref}",
"downloads_url": "https://api.github.com/repos/google/firmata.py/downloads",
"issues_url": "https://api.github.com/repos/google/firmata.py/issues{/number}",
"pulls_url": "https://api.github.com/repos/google/firmata.py/pulls{/number}",
"milestones_url": "https://api.github.com/repos/google/firmata.py/milestones{/number}",
"notifications_url": "https://api.github.com/repos/google/firmata.py/notifications{?since,all,participating}",
"labels_url": "https://api.github.com/repos/google/firmata.py/labels{/name}",
"releases_url": "https://api.github.com/repos/google/firmata.py/releases{/id}",
"deployments_url": "https://api.github.com/repos/google/firmata.py/deployments",
"created_at": "2013-03-27T23:20:35Z",
"updated_at": "2019-09-23T11:54:02Z",
"pushed_at": "2013-03-27T23:34:35Z",
"git_url": "git://github.com/google/firmata.py.git",
"ssh_url": "git@github.com:google/firmata.py.git",
"clone_url": "https://github.com/google/firmata.py.git",
"svn_url": "https://github.com/google/firmata.py",
"homepage": None,
"size": 160,
"stargazers_count": 15,
"watchers_count": 15,
"language": "Python",
"has_issues": True,
"has_projects": True,
"has_downloads": True,
"has_wiki": True,
"has_pages": False,
"forks_count": 15,
"mirror_url": None,
"archived": False,
"disabled": False,
"open_issues_count": 0,
"license": {
"key": "apache-2.0",
"name": "Apache License 2.0",
"spdx_id": "Apache-2.0",
"url": "https://api.github.com/licenses/apache-2.0",
"node_id": "MDc6TGljZW5zZTI="
},
"forks": 15,
"open_issues": 0,
"watchers": 15,
"default_branch": "master",
"permissions": {
"admin": False,
"push": False,
"pull": True
}
}
],
['episodes.dart', 'cpp-netlib', 'dagger', 'ios-webkit-debug-proxy', 'google.github.io', 'kratu', 'build-debian-cloud', 'traceur-compiler', 'firmata.py'],
['dagger', 'kratu', 'traceur-compiler', 'firmata.py'],
)
]
Tasks
0. Parameterize a unit test
Familiarize yourself with the utils.access_nested_map function
and understand its purpose. Play with it in the Python console to make sure
you understand.
In this task you will write the first unit test for
utils.access_nested_map.
Create a TestAccessNestedMap class that inherits from
unittest.TestCase.
Implement the TestAccessNestedMap.test_access_nested_map method
to test that the method returns what it is supposed to.
Decorate the method with @parameterized.expand to test the
function for following inputs:
nested_map={"a": 1}, path=("a",)
nested_map={"a": {"b": 2}}, path=("a",)
nested_map={"a": {"b": 2}}, path=("a", "b")
For each of these inputs, test with assertEqual that the
function returns the expected result.
The body of the test method should not be longer than 2 lines.
Repo:
- GitHub repository:
alx-backend-python - Directory:
0x03-Unittests_and_integration_tests - File:
test_utils.py
1. Parameterize a unit test
Implement TestAccessNestedMap.test_access_nested_map_exception.
Use the assertRaises context manager to test that a
KeyError is raised for the following inputs (use
@parameterized.expand):
nested_map={}, path=("a",)
nested_map={"a": 1}, path=("a", "b")
Also make sure that the exception message is as expected.
Repo:
- GitHub repository:
alx-backend-python - Directory:
0x03-Unittests_and_integration_tests - File:
test_utils.py
2. Mock HTTP calls
Familiarize yourself with the utils.get_json function.
Define the TestGetJson(unittest.TestCase) class and implement
the TestGetJson.test_get_json method to test that
utils.get_json returns the expected result.
We don’t want to make any actual external HTTP calls. Use
unittest.mock.patch to patch requests.get. Make
sure it returns a Mock object with a json method
that returns test_payload which you parametrize alongside the
test_url that you will pass to get_json with the
following inputs:
test_url="http://example.com", test_payload={"payload": True}
test_url="http://holberton.io", test_payload={"payload": False}
Test that the mocked get method was called exactly once (per
input) with test_url as argument.
Test that the output of get_json is equal to
test_payload.
Repo:
- GitHub repository:
alx-backend-python - Directory:
0x03-Unittests_and_integration_tests - File:
test_utils.py
3. Parameterize and patch
Read about memoization and familiarize yourself with the
utils.memoize decorator.
Implement the TestMemoize(unittest.TestCase) class with a
test_memoize method.
Inside test_memoize, define following class
class TestClass:
def a_method(self):
return 42
@memoize
def a_property(self):
return self.a_method()
Use unittest.mock.patch to mock a_method. Test that
when calling a_property twice, the correct result is returned
but a_method is only called once using
assert_called_once.
Repo:
- GitHub repository:
alx-backend-python - Directory:
0x03-Unittests_and_integration_tests - File:
test_utils.py
4. Parameterize and patch as decorators
Familiarize yourself with the client.GithubOrgClient class.
In a new test_client.py file, declare the
TestGithubOrgClient(unittest.TestCase) class and implement the
test_org method.
This method should test that GithubOrgClient.org returns the
correct value.
Use @patch as a decorator to make sure get_json is
called once with the expected argument but make sure it is not executed.
Use @parameterized.expand as a decorator to parametrize the test
with a couple of org examples to pass to
GithubOrgClient, in this order:
googleabc
Of course, no external HTTP calls should be made.
Repo:
- GitHub repository:
alx-backend-python - Directory:
0x03-Unittests_and_integration_tests - File:
test_client.py
5. Mocking a property
memoize turns methods into properties. Read up on how to mock a
property (see resource).
Implement the test_public_repos_url method to unit-test
GithubOrgClient._public_repos_url.
Use patch as a context manager to patch
GithubOrgClient.org and make it return a known payload.
Test that the result of _public_repos_url is the expected one
based on the mocked payload.
Repo:
- GitHub repository:
alx-backend-python - Directory:
0x03-Unittests_and_integration_tests - File:
test_client.py
6. More patching
Implement TestGithubOrgClient.test_public_repos to unit-test
GithubOrgClient.public_repos.
Use @patch as a decorator to mock get_json and make
it return a payload of your choice.
Use patch as a context manager to mock
GithubOrgClient._public_repos_url and return a value of your
choice.
Test that the list of repos is what you expect from the chosen payload.
Test that the mocked property and the mocked get_json was called
once.
Repo:
- GitHub repository:
alx-backend-python - Directory:
0x03-Unittests_and_integration_tests - File:
test_client.py
7. Parameterize
Implement TestGithubOrgClient.test_has_license to unit-test
GithubOrgClient.has_license.
Parametrize the test with the following inputs
repo={"license": {"key": "my_license"}}, license_key="my_license"
repo={"license": {"key": "other_license"}}, license_key="my_license"
You should also parameterize the expected returned value.
Repo:
- GitHub repository:
alx-backend-python - Directory:
0x03-Unittests_and_integration_tests - File:
test_client.py
8. Integration test: fixtures
We want to test the GithubOrgClient.public_repos method in an
integration test. That means that we will only mock code that sends external
requests.
Create the TestIntegrationGithubOrgClient(unittest.TestCase)
class and implement the setUpClass and
tearDownClass which are part of the
unittest.TestCase API.
Use @parameterized_class to decorate the class and parameterize
it with fixtures found in fixtures.py. The file contains the
following fixtures:
org_payload, repos_payload, expected_repos, apache2_repos
The setupClass should mock requests.get to return
example payloads found in the fixtures.
Use patch to start a patcher named get_patcher, and
use side_effect to make sure the mock of
requests.get(url).json() returns the correct fixtures for the
various values of url that you anticipate to receive.
Implement the tearDownClass class method to stop the patcher.
Repo:
- GitHub repository:
alx-backend-python - Directory:
0x03-Unittests_and_integration_tests - File:
test_client.py
9. Integration tests
Implement the test_public_repos method to test
GithubOrgClient.public_repos.
Make sure that the method returns the expected results based on the fixtures.
Implement test_public_repos_with_license to test the
public_repos with the argument
license="apache-2.0" and make sure the result matches the
expected value from the fixtures.
Repo:
- GitHub repository:
alx-backend-python - Directory:
0x03-Unittests_and_integration_tests - File:
test_client.py